﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Google.Apis.Drive.v3;

namespace GoogleDriveAPI
{
    public class GDriveFolderAPI
    {
        private GDriveService gDriveService;
        private DriveService driveService;

        public GDriveFolderAPI()
        {
            this.gDriveService = GDriveService.Instance;
            this.driveService = this.gDriveService.GetDriveService();
        }

        /// <summary>
        /// Get all folders include child folders and parent folders.
        /// </summary>
        /// <returns>A list of GoogleDriveFolder</returns>
        public async Task<List<GDriveFolder>> GetAll()
        {
            FilesResource.ListRequest listRequest = driveService.Files.List();
            listRequest.Q = "mimeType='application/vnd.google-apps.folder'";
            IList<Google.Apis.Drive.v3.Data.File> folders = (await listRequest.ExecuteAsync()).Files.ToList();

            List<GDriveFolder> listFolder = new List<GDriveFolder>();
            GDriveFileAPI fileApi = new GDriveFileAPI();
            foreach (var folder in folders)
            {
                listFolder.Add(new GDriveFolder
                {
                    Id = folder.Id,
                    Name = folder.Name,
                    MimeType = folder.MimeType,
                    WebViewLink = folder.WebViewLink,
                    WebContentLink = "",
                    Parents = folder.Parents,
                    Contents = await fileApi.GetFilesInFolderAsync(folder.Id),
                    CreatedTime = folder.CreatedTime,
                    ModifiedTime = folder.ModifiedTime
                });
            }
            return listFolder;
        }

        /// <summary>
        /// Get folder by folderId
        /// </summary>
        /// <param name="folderId">Id of the folder</param>
        /// <returns>A GoogleDriveFolder if the folder is found or null.</returns>
        public async Task<GDriveFolder> Get(string folderId)
        {
            if (!String.IsNullOrEmpty(folderId) && !String.IsNullOrWhiteSpace(folderId))
            {
                Google.Apis.Drive.v3.Data.File folder = null;
                try
                {
                    FilesResource.GetRequest getRequest = driveService.Files.Get(folderId);
                    folder = await getRequest.ExecuteAsync();

                    if (folder == null) return null;

                    GDriveFileAPI fileApi = new GDriveFileAPI();
                    return new GDriveFolder
                    {
                        Id = folder.Id,
                        Name = folder.Name,
                        MimeType = folder.MimeType,
                        WebViewLink = folder.WebViewLink,
                        WebContentLink = "",
                        Parents = folder.Parents,
                        Contents = await fileApi.GetFilesInFolderAsync(folder.Id),
                        CreatedTime = folder.CreatedTime,
                        ModifiedTime = folder.ModifiedTime
                    };
                }
                catch (Google.GoogleApiException ex)
                {
                    Console.Write(ex.Message);
                }
            }

            return null;
        }

        /// <summary>
        /// Create a folder
        /// </summary>
        /// <param name="folderName">Name of the folder.</param>
        /// <param name="parentId">Parent folder id.</param>
        /// <returns>A GoogleDriveFolder if it's created successfully, null if not.</returns>
        public async Task<GDriveFolder> Create(string folderName, string parentId = null)
        {
            if (String.IsNullOrEmpty(folderName) || String.IsNullOrWhiteSpace(folderName))
            {
                try
                {
                    // Create parents list
                    List<String> parents = null;
                    if (parents != null)
                    {
                        parents.Add(parentId);
                    }

                    // Make a create request
                    Google.Apis.Drive.v3.Data.File folder = null;
                    FilesResource.CreateRequest createRequest = driveService.Files.Create(
                        new Google.Apis.Drive.v3.Data.File
                        {
                            MimeType = "application/vnd.google-apps.folder",
                            Name = folderName,
                            Parents = parents
                        });
                    folder = await createRequest.ExecuteAsync();

                    return Convert(folder);
                }
                catch (Google.GoogleApiException ex)
                {
                    Console.Write(ex.Message);
                }
            }
            return null;
        }

        /// <summary>
        /// Permanent delete file from server, not moving to trash.
        /// </summary>
        /// <param name="folderId">Id of the folder.</param>
        public async Task Delete(string folderId)
        {
            if (!String.IsNullOrWhiteSpace(folderId) && !String.IsNullOrEmpty(folderId))
            {
                try
                {
                    FilesResource.DeleteRequest deleteRequest = driveService.Files.Delete(folderId);
                    await deleteRequest.ExecuteAsync();
                }
                catch (Google.GoogleApiException ex)
                {
                    Console.Write(ex.Message);
                }
            }
        }

        /// <summary>
        /// Update existed folder with new metadata.
        /// </summary>
        /// <param name="folderId">Id of the folder.</param>
        /// <param name="folderMetadata">Folder metadata</param>
        /// <returns></returns>
        public async Task<GDriveFolder> Update(string folderId, GDriveFolder folderMetadata)
        {
            if (!String.IsNullOrWhiteSpace(folderId) || !String.IsNullOrEmpty(folderId))
            {

                try
                {
                    FilesResource.UpdateRequest updateRequest = driveService.Files.Update(new Google.Apis.Drive.v3.Data.File
                    {
                        Name = folderMetadata.Name,
                        ModifiedTime = folderMetadata.ModifiedTime,
                        Parents = folderMetadata.Parents,
                        Description = folderMetadata.Description
                    }, folderId);

                    Google.Apis.Drive.v3.Data.File folder = await updateRequest.ExecuteAsync();
                    return Convert(folder);
                }
                catch (Google.GoogleApiException ex)
                {
                    Console.Write(ex.Message);
                }
            }
            return null;
        }

        /// <summary>
        /// Convert Google.Apis.Drive.v2.Data.File to new object type GoogleDriveFolder.
        /// </summary>
        /// <param name="folder">Folder type Google.Apis.Drive.v3.Data.File</param>
        /// <returns>Object type GoogleDriveFile</returns>
        private GDriveFolder Convert(Google.Apis.Drive.v3.Data.File folder)
        {
            return new GDriveFolder
            {
                Id = folder.Id,
                Name = folder.Name,
                ThumbnailUrl = folder.ThumbnailLink,
                WebViewLink = folder.WebViewLink,
                Description = folder.Description,
                CreatedTime = folder.CreatedTime,
                ModifiedTime = folder.ModifiedTime,
                Parents = folder.Parents
            };
        }
    }

    public class GDriveFolder : GDriveFile
    {
        public IList<GDriveFile> Contents { get; set; }

        public GDriveFolder()
        {
            this.MimeType = "application/vnd.google-apps.folder";
        }
    }
}
